F�r diesen Algorithmus gilt vieles, was bereits zum Scroller_XUnlimited gesagt wurde. Sehen Sie sich deshalb unbedingt zuerst dessen Dokumentation an!

Der gro�e Unterschied besteht darin, da� die Bitmap nicht mehr doppelt breit ist. Bei den 1x und 2x FETCH Modi kommen wir mit einer EXTRABREITE von 32 (2 * BLOCKBREITE) , beim 4x FETCH Modus m�ssen wir 64 Pixel EXTRABREITE verwenden, damit die Bitmapbreite ein Vielfaches von 64 ist. Somit betr�gt die Bitmapbreite 352 bzw. 384 Pixel. Wir werden auch nicht mehr doppelt blitten, und dadurch ist dieser Alogrithmus doppelt so schnell.

Wie bereits in der �bersichtstabelle zu sehen war, h�ngt die Bitmaph�he von der Levelbreite ab. Das ist deshalb so, weil wir beim Nach-Rechts-Scrollen einfach munter die Plane-Start-Adressen erh�hen (beim Nach-Links-Scrollen entsprechend vermindern) und sich deshalb der Start und das Ende der sichtbaren Bitmap im Speicher nach hinten verschiebt. Scrollen wir zum Beispiel 16 Pixel nach rechts, dann sind die Plane-Start-Adressen auf ECHTE-BITMAP-STARTADRESSE + 2 Bytes (beim Chunky Pixel Modus = Grafikkarten w�ren es 16 Bytes!) zu setzen. Das hei�t somit, da� die Bitmap 2 Bytes gr��er sein mu�, wenn wir maximal 16 Pixel nach rechts scrollen. Bei 32 Pixeln w�ren es 4 Bytes, usw. Denkt man an �bergro�e (autoscrollende) Screens, ist man leicht dazu verleitet zu denken, es w�rden viel mehr Bytes notwendig (16 Pixel: (2 * 256 * ANZPLANES)) sein. Das stimmt aber nicht, denn im Gegensatz zu diesen Screens befinden sich nicht andauernd die gesamten Grafikdaten in der Bitmap, sondern nur ein kleiner Ausschnitt (352 * 256 oder 384 * 256 Pixel). Scrollen wir nach rechts, so verschwindet links ein Teil und erscheint rechts planeversetzt (auf Grafikkarten bzw. Bitmaps im nicht-interleavten Format zeilenversetzt), wir k�nnen also dort den rechts hereinkommenden Levelbereich blitten. Beim Nach-Links-Scrollen ist es genau umgekehrt. Falls wir die Bitmap mit AllocBitmap() erzeugen, dann errechnet sich die Gesamth�he der Bitmap wie folgt:

  gesamtbitmaph�he = BITMAPH�HE + (LEVELBREITE : BITMAPBL�CKEPROREIHE : ANZPLANES) + 1

BITMAPH�HE ist die eigentlich gew�nschte Bitmaph�he, in unserem Fall also 256 Pixel. LEVELBREITE ist die Breite des Levels in Bl�cken. BITMAPBL�CKEPROREIHE entspricht BITMAPBREITE : BLOCKBREITE, d. h. in unserem Falle 22 (1x und 2x FETCH Modus) bzw. 24 (4x FETCH Modus).

Das Demoprogramm zu diesem Algorithmus verwendet ein Level, das 1000 Bl�cke breit ist. Das sind 16000 Pixel oder 50 Screens. Das ist schon relativ gro� und dennoch ergibt sich aus obiger Formel eine sehr kleine Bitmapgesamth�he - insgesamt also eine riesige Speicherersparnis im Gegensatz zum Scroller_XUnlimited Algorithmus, vor allem wenn man bedenkt, da� so gut wie alle Spiele Triple- oder zumindest Double-Buffering verwenden:

  gesamtbitmaph�he = 256 + (1000 : 22 : 4) + 1
  gesamtbitmaph�he = 256 + 11 + 1
 
  gesamtbitmaph�he = 268

268 Pixel Gesamtbitmaph�he (f�r den 4x FETCH Modus ergibt die Rechnung 267 Pixel) sind extrem wenig, bedenkt man die Gr��e des Levels. Selbst ein wahrlich riesiges Level von 200 Screens Breite (64000 Pixel) ben�tigt nur eine Gesamtbitmaph�he von 301 bzw. 297 Pixeln. Noch immer eine gigantische Speicherersparnis im Gegensatz zum Scroller_XUnlimited Algorithmus. Auf Grafikkarten oder bei Bitmaps im nicht-interleavten Format w�rde die Sache �brigens um einiges mehr an Speicher verschlingen. Im Gegensatz zu 2 Bytes pro 16 Pixel Scrolling bei einer interleavten Amiga-Planar-Bitmap sind das bei einer Grafikkarte, die Chunky-Pixel verwendet, 16 Bytes pro 16 Pixel Scrolling und bei einer nicht-interleavten Amiga-Planar-Bitmap immer noch 2 Bytes * ANZPLANES.

In den nachfolgenden Beschreibungen gehe ich vom 1x bzw. 2x FETCH Modus aus, also einer Bitmapbreite von 352 Pixeln. Am Anfang f�llen wir die Bitmap mit dem zuerst sichtbaren Levelbereich:

Das rote Rechteck stellt den am Anfang aktuellen Bitmapbereich dar, w�hrend das gelbe Rechteck den am Anfang sichtbaren Bereich darstellt. Beachten Sie den am unteren Rand freien Bereich, der erst genutzt (und mehr und mehr genutzt) wird, wenn wir nach rechts scrollen. Nehmen wir an, wir wollen 16 Pixel nach rechts. Der akutelle Bitmapbereich und mit ihm der sichtbare Bereich verschieben sich dadurch 16 Pixel nach rechts, die "aktuelle Bitmap" also 2 Bytes nach hinten im Speicher. Das sieht dann so aus:

Das Ende des roten Rechtecks und somit des aktuellen Bitmapbereiches l�uft nicht �ber das rechte Ende der Bitmap hinaus, weil dort nichts ist (kein Speicher) sondern "wrappt" sozusagen auf die linke Seite. Die vergr��ert dargestellten Bereiche verdeutlichen, da� der dortige Bereich um eine "Planeline" (1 Pixelzeile besteht aus ANZPLANES Planelines) nach unten verschoben ist. Die folgenden zwei Bilder verdeutlichen warum das so ist. Das erste Bild stellt zwei Pixelzeilen dar, wie sie sich im Speicher befinden. Die Zahlen in den K�stchen, welche f�r jeweils 16 Pixel stehen, zeigen den jeweiligen Offset von der Bitmap Adresse in Bytes. Bei diesem Bild gehen wir davon aus, da� wir die Bitmap ab Offset 0 darstellen:

Beim zweiten Bild soll der Videochip die Bitmap ab Offset 2 darstellen. Wie im Bild ersichtlich holt sich die Video DMA stets Daten von Offsets in aufsteigender Folge. An der rechten Bitmapgrenze angelangt befindet sich z. B. in der 1. Zeile (= Zeile 0) der Plane 0 Pointer bei Offset 42. Der n�chsth�here Offset ist Offset 44, und der befindet sich am linken Bitmaprand, aber nicht in derselben Planeline, sondern eine Planeline darunter:

Die X-Position der Nachf�llspalte in der Bitmap befindet sich wie beim Scroller_XUnlimited Alogrithmus stets an der Stelle des aktuellen Bitmapbereiches (rotes Rechteck) abgerundet auf ein Vielfaches der Blockbreite, also:

videoposx & ~(BLOCKBREITE - 1)

Bei der Y-Position ist das ein bi�chen anders. Beim Scroller_XUnlimited Alogrithums war sie stets ganz oben in der Bitmap. Hier jedoch erh�hen wir videoposx wenn wir nach rechts scrollen andauernd, ohne diese Variable ab einem bestimmten Wert wieder auf 0 zu setzen. Deshalb wandert die Nachf�llspalte langsam nach unten in der (echten) Bitmap. Das geschieht ganz automatisch und ist nicht das Problem, weil wir beim Blitten der Bl�cke ja stets videoposx mit einbeziehen, d. h. zu den ZielX Koordinaten dazuz�hlen, was indirekt die echte ZielY Koordinate �ndert bzw. �ndern kann. Ein Koordinatenpaar (x=0,y=1), wobei die Einheit von y Planelines sind (1 Pixellinie besteht aus ANZPLANES Planelines), entspricht z. B. dem Koordinatenpaar (x=352,y=0), wenn wir eine Bitmapbreite von 352 Pixeln voraussetzen.

Wie weiter oben beschrieben, ist zu beachten, da� beim Nach-Rechts-Scrollen links verschwindende Bereich auf der rechten Seite versetzt um eine Planeline nach unten vom Video CHIP dargestellt werden. Aus der Sicht der Bitmap befindet sich der planeversetzte Bereich auf der linken Seite. Genau in diesen Bereich m�ssen wir blitten, denn es ist der Bereich der rechts hereinkommt. Da er planeversetzt ist, m�ssen wir auch planeversetzt zeichnen, d. h. die echte ZielY-Koordinate der jeweilig zu blittenden Bl�cke mu� um eine Planeline erh�ht werden. Am einfachsten geht das, indem wir zur ZielX-Koordinate (X nicht Y!) BITMAPBREITE (352) dazuz�hlen, denn das kommt auf das genau gleiche hinaus. Indem wir das machen, brauchen wir uns um Y-Koordinaten nicht besondern zu k�mmern, sondern k�nnen immer davon ausgehen, da� die Nachf�llspalte an Y Position 0 beginnt.

Nachdem wir z. B. 2 Pixel nach rechts gescrollt sind, sieht die Bitmap schematisch dargestellt so aus:

Die gelben Rechtecke stellen die geblitteten = neu hereingekommenen Bl�cke dar. Sie sind gegen�ber den anderen Bl�cken um eine Planeline nach unten versetzt geblittet worden. Wenn wir jetzt wieder 1 Pixel nach links wollen, dann mu� der 2. gelbe Block der zur Zeit Block (22,1) ist (d. h. 23. Block aus 2. Levelreihe) wieder durch Block (0,1) (d.h 1. Block aus 2. Levelreihe) ersetzt werden. Wie an den anderen nicht-gelben Bl�cken ersichtlich, d�rfen wir beim Nach-Links-Scrollen die Bl�cke nicht plane-versetzt blitten, deshalb z�hlen wir zur ZielX-Koordinate diesmal auch nicht BITMAPBREITE dazu. Nach dem Blitten ergibt sich ein kleines Problem, wie im folgenden Bildes zu erkennen ist:

Da wir beim Nach-Rechts-Scrollen plane-versetzt geblittet haben zerst�rte der 2. gelbe Block zwei "alte" Bl�cke. Beim zweiten zerst�rten Block ist das zwar nur eine Planeline (bei einer Blockbreite von 16 Pixeln also 2 Byte = 1 Word), aber Grafikfehler ist Grafikfehler. Deshalb m�ssen wir auch diesen Bereich "restaurieren" - wie, sehen wir sp�ter. Wir befinden uns jetzt an Levelposition 1. Wenn wir jetzt wieder ein Pixel nach rechts wollen um Levelposition 2 zu erreichen, dann ergibt sich ein �hnliches Problem:

Beim Nach-Links-Scrollen um ein Pixel haben wir teilweise auch den 1. gelben Block �berblittet, deshalb reicht es beim Nach-Rechts-Scrollen nicht aus nur den 2. gelben Block zu blitten. Wir m�ssen auch die zerst�rten Teile des 1. gelben Blockes restaurieren.

Das alles klingt nach viel Arbeit, ist aber ganz einfach. Wenn man sich die vorigen drei Bilder genauer ansieht, merkt man, da� beim Nach-Rechts-Scrollen der Blit die erste Planeline = die ersten 2 Bytes des n�chsten (darunter liegenden) Blockes trasht. Beim Nach-Links-Scrollen hingegen trasht der Blit die letzte Planeline = die letzten 2 Bytes des vorherigen (dar�ber liegenden) Blockes.

Wir l�sen das Problem so: Vor dem Blitten von plane-versetzten Bl�cken, d. h. wenn wir nach rechts scrollen, machen wir ein Backup von der letzten Block-Planeline in der Bitmap, die �berblittetet werden wird - das ist die 1. Planeline (= 1. Zeile, 1. Plane) des n�chsten (nicht planeversetzt darunter liegenden) Blockes. Die Planeline ist nur 2 Bytes gro�, also merken wir uns die Planeline in einer ganz normalen 16 Bit UWORD Variable. Im Quelltext hat sie den Namen saveword. Wir merken uns auch die Speicheradresse, wo wir den Inhalt der Planeline ausgelesen haben, weil wir sie sp�ter zum Restaurieren brauchen. Im Quelltext wird dazu die Variable savewordpointer benutzt.

Vor dem Blitten von nicht-plane-versetzten Bl�cken, d. h. wenn wir nach links scrollen, machen wir ein Backup von der ersten Block-Planeline in der Bitmap, die �berblittet werden wird - das ist die letzte Planeline (= letzte Zeile, letztes Plane) des vorherigen (planeversetzt dar�ber liegenden) Blockes. Wieder speichern wir den Inhalt der Planeline in einer Variablen und merken uns auch die Adresse der Planeline, um beim Restaurieren nicht alles neu berechnen zu m�ssen.

Wenn st�ndig in eine Richtung gescrollt wird, dann ist keine Restauration notwendig. Die braucht es nur, wenn wir die Richtung �ndern. Das Backup hingegen wird immer gemacht. In Pseudo-Code sieht das in etwa so aus:

 SCROLL_LINKS:

   /* Restauration */

   wenn (Vorige_ScrollRichtung == RECHTS)
   {
       kopiere saveword nach savewordpointer
   }
   
   /* Backup */

   savewordpointer = Adresse der ersten Planeline die �berblittet werden wird
   saveword = Inhalt von savewordpointer

   /* Blit */
   
   Block blitten
   
   Vorige_ScrollRichtung = LINKS

   return



 SCROLL_RECHTS:

   /* Restauration */

   wenn (Vorige_ScrollRichtung == LINKS)
   {
       kopiere saveword nach savewordpointer;
   }
   
   /* Backup */

   savewordpointer = Adresse der letzten Planeline die �berblittet werden wird;
   saveword = Inhalt von savewordpointer

   /* Blit */
   
   Block blitten
   
   Vorige_ScrollRichtung = RECHTS

   return

Bei Verwendung von 2x und 4x FETCH Modi ist zu beachten, da� wir uns genau gleich wie beim Scroller_XUnlimited Alogrithmus den zu verdeckenden Bereich an die richtige Stelle schieben m�ssen. Das l�sen wir wieder so, da� beim Rendern/Blitten in die Bitmap ein Offset von 2 (2x FETCH Modus) bzw. 6 (4x FETCH Modus) Bytes verwendet wird. Nat�rlich darf man dabei beim Allozieren der Bitmap nicht vergessen, eine Zeile (bei Verwendung von AllocBitmap()) oder 2 bzw. 6 Bytes (bei Verwendung von AllocMem()) mehr anzufordern.

Noch einige Bemerkungen zum Quelltext des Demoprogrammes. Wenn die Variable mapposx, die die Levelposition X in Pixeln enth�lt, auf 0 steht, dann sieht der User den Levelbereich ab Position BLOCKBREITE (16), weil die ersten BLOCKBREITE (16) Pixel stets verdeckt sind. Der User sieht also den Bereich:

(mapposx + BLOCKWIDTH,0) - (mapposx + BLOCKWIDTH + SCREENWIDTH - 1,SCREENHEIGHT - 1)

Das hei�t, da� die erste Blockspalte der Leveldatei nie sichtbar ist. Will man in die Bitmap etwas hineinblitten, z. B. Blitter Objekte (BOBs), dann mu� man das im aktuell sichtbaren Bitmapbereich machen. Dieser Bereich ist:

(videoposx + BLOCKWIDTH,0) - (videoposx + BLOCKWIDTH + SCREENWIDTH - 1,SCREENHEIGHT - 1)

Man darf die Start-X Koordinate (videoposx + BLOCKWIDTH) und die End-X Koordinate (videoposx + BLOCKWIDTH + SCREENWIDTH - 1) auf ein Vielfaches von BLOCKWIDTH auf- bzw. abrunden, soda� der Bereich, in den geblittet werden darf insgesamt SCREENWIDTH + BLOCKWIDTH Pixel breit ist:

blitbereich_strtx = (videoposx + BLOCKWIDTH) & ~(BLOCKWIDTH - 1)

blitbereich_endex = blitbereich_strtx + SCREENWIDTH + BLOCKWIDTH - 1

Grundlage f�rs Blitten mu� immer die Variable frontbuffer sein, weil diese in den 2x und 4x FETCH Modi nicht identisch mit der echten Bitmapadresse ist! Beim Quelltext zu diesem Algorithmus haben die Variablen mapposx und videoposx stets die gleichen Werte. Bei gro�en Levels wird man deshalb einige Variablen und Funktionsparameter von 16 Bit auf 32 Bit �ndern m�ssen, um einen �berlauf zu verhindern. 1 Pixel Scrolling bedeutet auch eine Erh�hung/Verminderung um 1 der Variablen videoposx!